

let Network = require('Network')

class NetClient 
{
    constructor(httpURL) 
    {
        this.mHttpURL  = httpURL
        this.mClientOk = false

	    this.mToConnecting = false
        this.mPredefineResponses = null//require('SocketResponse')

        this.mResponses = {} 

        let NetCrypt = require('NetCrypt')

        this.mCrypt    = new NetCrypt('f749fa3063585e68f73f37b842b5472c')

        this.mSyncer = require('NetDataSyncer')
    }

    updateSession(session)
    {
        this.mSession = session
    }

    connectToServer(url, connectCallback)
    {
        if (this.mConnect)
        {
            Log.w("NetClient", "fail to connect server: connect object ok." + url)

            return
        }

        this.mServerUrl    = url

        let SocketConnect = require('SocketConnect')

        this.mConnect = new SocketConnect()
        
        this.mConnect.connect(url, 
            (connect)=> //onConnectSuccessFucs
            {
                Log.d('NetClient', 'socket connect ok: ' + url)

                if (connectCallback)
                {
                    connectCallback(connect, true)
                }
            }, 

            (connect) => //onDisconnect
            {
                Log.w("NetClient", "socket disconnect : " + url)

                if (this.mConnect == connect)
                {
                    this.close()
                }
                else
                {
                    connect.close()
                    Log.w("NetClient", "socket disconnect, not effect connect : " + url)
                }
            }, 

            (connect) => 
            {  
                //onConnectErrorFucs
                if (connect != this.mConnect)
                {
                    Log.e('NetClient', 'socket error, not effect connect..')

                    return
                }

                Log.e('NetClient', 'socket disconnect..')
		   
                this.onDisconnect()
            },

            (connect, d)=>{

                if (this.mConnect != connect)
                {
                    return
                }

                let r = this.mCrypt.decode(d)

                if (!r)
                {
                    r = JSON.parse(d)
                }

                if (r && r.m)
                {
                    let cmd = r.m

                    let response = this.mResponses[cmd]
                    if (response)
                    {
                        this.mResponses[cmd] = null
                    }
                    else
                    {
                        response = this.mPredefineResponses[cmd]
                    }
                    response(r)
                }
                else
                {
                    Log.w('NetClient', 'socket callback not json data or cmd null: ' + d)
                }
            }
        )
    }

    startBeat()
    {
        if (!this.mConnect)
        {
            return
        }
                        
        let m = '9999'

        let onBeat = this.mConnect.startBeat(
            this.mCrypt.encode( { m : m } ), 
            5000, 
            4, 
            () =>{
                if (this.mConnect)
                {
                    this.mConnect.stopBeat()
                }
            }
        )

        this.mPredefineResponses[m] = (d) =>{

                if (d && d.time)
                {
                    onBeat(d.time)

                    Log.d('NetClient', 'server time: '+ d.time)
                }
            }
        Log.d('NetClient', 'socket connect ok, start heart beat.')
    }

    stopBeat()
    {
        if (this.mConnect)
        {
            this.mConnect.stopBeat()
        }
    }

    close()
    {
        this.mDisconnectNotifyer = null
        if (this.mConnect)
        {
            this.mConnect.close()

            this.mConnect = null
        }
        this.mResponses = {}

        Log.w("NetClient", "close : " + (this.mServerUrl || ''))
    }

    requestSocket(data, callback)
    {
        if (this.mClientOk && this.mConnect)
        {
            if (this.mCrypt)
            {
                if (data.m)
                {
                    this.mResponses[data.m] = callback
                }
                Log.d("Network, socket send: ", JSON.stringify(data))
                this.mConnect.send(this.mCrypt.encode(data))
            }
            else
            { 
                this.mConnect.send(JSON.stringify(data))
            }
        }
    }

    http(url, data, headers, callback, method, type, uid)
    {
        let d = this.mCrypt.encodeHttp(data, this.mSession, uid)

        if (d.sign)
        {
            if (headers)
            {
                headers.sign = d.sign
            }
            else
            {
                headers = { sign : d.sign }
            }
        }

        if (uid)
        {
            if (headers)
            {
                headers.uid = uid
            }
            else
            {
                headers = { uid : uid }
            }
        }

        let times = 3

        let request = () =>{

            Network.httpRequest(url, d.msg, headers, 
                (m)=>{
                    if (m)
                    {
                        let r = this.mCrypt.decode(m)

                        if (!r)
                        {
                            r = JSON.parse(m)
                        }

                        if (r != null && r != undefined)
                        {
                            this.mSyncer(r)
                            
                            callback(r)
                        }
                        else
                        {
                            callback(m)
                        }
                    }
                    else
                    {
                        --times
                        if (times < 0)
                        {
                            callback()
                        }
                        else
                        {
                            request()
                        }
                    }
                }, 
                method, type)
        }
        request()
    }

    httpCmd(cmd, data, callback, version, type)
    {
        let url = this.mHttpURL + cmd

        url += version ? ("/" + version) : "/1"

        this.http(url, data, null, callback, null, type)
    }

    reconnect(callback)
    {
        if (this.mToConnecting)
        {
            Log.e('NetClient', 'reconnect fail, mToConnecting true')
            return
        }

        Log.d('NetClient', 'try reconnect ...')

        if (this.mConnect)
        {
            this.mConnect(
                (ok)=>{
    
                    if (ok)
                    {
                        this.startBeat()
                    }
                    callback && callback(ok)
                }
            )
        }
    }

    isConnected()
    {
        return this.mClientOk
    }
	
    onDisconnect()
    {
     
        this.mClientOk = false
	
	    if (this.mDisconnectNotifyer)
        {
            this.mDisconnectNotifyer()
        }
    }
    
    setDisconnectNotifyer(ner)
    {
        this.mDisconnectNotifyer = ner
    }

    time()
    {
        if (this.mConnect)
        {
            return this.mConnect.time()
        }

        return cc.sys.now()
    }
}

export default NetClient
